/*
 * @(#)ToolBarButtonFactory.java  1.2  2006-07-16
 *
 * Copyright (c) 1996-2006 by the original authors of JHotDraw
 * and all its contributors ("JHotDraw.org")
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * JHotDraw.org ("Confidential Information"). You shall not disclose
 * such Confidential Information and shall use it only in accordance
 * with the terms of the license agreement you entered into with
 * JHotDraw.org.
 */

package umage.core;

import org.jhotdraw.util.*;
import org.jhotdraw.draw.action.*;
import java.util.Comparator;
import java.util.List;
import java.awt.Container;
import java.awt.event.*;
import java.lang.reflect.Constructor;
import java.util.*;
import javax.swing.*;
import org.jhotdraw.app.action.*;
import org.jhotdraw.draw.*;

import umage.figures.FigureInfo;

/**
 * ToolBarButtonFactory.
 *
 * @author Werner Randelshofer
 * @version 1.2 2006-07-16 Split some methods up for better reuse. 
 * <br>1.1 2006-03-27 Font exclusion list updated.
 * <br>1.0 13. Februar 2006 Created.
 */
public class UMageButtonManager {
    
    protected static class ToolButtonListener implements ItemListener {
        private Tool tool;
        private DrawingEditor editor;
        public ToolButtonListener(Tool t, DrawingEditor editor) {
            this.tool = t;
            this.editor = editor;
        }
        public void itemStateChanged(ItemEvent evt) {
            if (evt.getStateChange() == ItemEvent.SELECTED) {
                editor.setTool(tool);
            }
        }
    }
    
    protected static class PriorityToolbar {
    	public JToolBar toolbar;
    	public int priority;
    	
    	public PriorityToolbar(JToolBar toolbar, int priority) {
    		this.toolbar = toolbar;
    		this.priority = priority;
    	}
    }
    
    protected HashMap<String, PriorityToolbar> toolbars;
    protected HashMap<Class<? extends Figure>, JToggleButton> buttons;
    protected ButtonGroup group;
    protected ToolListener toolHandler;
    protected DrawingEditor editor;
    protected JToggleButton defaultToolButton;
    
    public UMageButtonManager(DrawingEditor editor) {
    	toolbars = new HashMap<String, PriorityToolbar>();
    	buttons = new HashMap<Class<? extends Figure>, JToggleButton>();
    	group = new ButtonGroup();
    	this.editor = editor;
    	addSelectionTool();
    }
    
    public static Collection<Action> createDrawingActions(DrawingEditor editor) {
        LinkedList<Action> a = new LinkedList<Action>();
        a.add(new CutAction());
        a.add(new CopyAction());
        a.add(new PasteAction());
        a.add(new SelectAllAction());
        a.add(new SelectSameAction(editor));
        
        return a;
    }
    
    public static Collection<Action> createSelectionActions(DrawingEditor editor) {
        LinkedList<Action> a = new LinkedList<Action>();
        a.add(new DuplicateAction());
        
        a.add(null); // separator
        a.add(new GroupAction(editor));
        a.add(new UngroupAction(editor));
        
        a.add(null); // separator
        a.add(new MoveToFrontAction(editor));
        a.add(new MoveToBackAction(editor));
        
        return a;
    }
    
    public void addSelectionTool() {
        addSelectionTool(createDrawingActions(editor), createSelectionActions(editor));
    }
    
    public void addSelectionTool(Collection<Action> drawingActions, Collection<Action> selectionActions) {
        ResourceBundleUtil labels = ResourceBundleUtil.getLAFBundle("org.jhotdraw.draw.Labels");
        
        JToggleButton t;
        Tool tool;
        HashMap<String,Object> attributes;
        
        // Selection tool
        Tool selectionTool = new DelegationSelectionTool(
                drawingActions, selectionActions
                );
        editor.setTool(selectionTool);
        t = new JToggleButton();
        defaultToolButton = t;
        
    	toolHandler = new ToolListener() {
            public void toolStarted(ToolEvent event) {}
            
            public void toolDone(ToolEvent event) {
                defaultToolButton.setSelected(true);
            }
            
            public void areaInvalidated(ToolEvent e) {}
        };
        
        labels.configureToolBarButton(t, "selectionTool");
        t.setSelected(true);
        t.addItemListener(
                new ToolButtonListener(selectionTool, editor)
                );
        t.setFocusable(false);
        group.add(t);
        getToolbar("Figures", 0).add(t);
    }
    
    /**
     * Method addSelectionToolTo must have been invoked prior to this on the
     * JToolBar.
     *
     */
    public void addTool(Class<? extends Figure> figure) {
    	
    	FigureInfo figureInfo = figure.getAnnotation(FigureInfo.class);
    	String name;
    	Icon icon;
    	String toolbar;
    	int toolbarPriority;
    	Class<? extends Tool> toolClass;
    	if (figureInfo != null) {
    		name = figureInfo.name();
    		icon = ImageUtil.getImageIcon(figureInfo.icon(), "/umage/figures/images/");
    		toolbar = figureInfo.toolbar();
    		toolbarPriority = figureInfo.toolbarPriority();
    		toolClass = figureInfo.tool();
    	} else return; // Just ignore figures without figure info
    	
    	Tool tool = createTool(toolClass, figure);
    	if (tool == null) return;
    	
        JToggleButton t = getToggleButton(figure);
        t.setText(null);
        t.setIcon(icon);
        t.setToolTipText(name);
        t.addItemListener(new ToolButtonListener(tool, editor));
        t.setFocusable(false);
        tool.addToolListener(toolHandler);
        group.add(t);
        getToolbar(toolbar, toolbarPriority).add(t);
    }
    
    protected Tool createTool(Class<? extends Tool> toolClass,
			Class<? extends Figure> figure) {
    	
    	// Construct the figure seperately to isolate errors from it
    	Figure f = null;
    	try {
			f = figure.newInstance();
		} catch (InstantiationException e) {
			System.err.println("Zero argument figure constructor is not public or does not exist");
			return null;
		} catch (IllegalAccessException e) {
			System.err.println("Zero argument figure constructor is not public or does not exist");
			return null;
		} catch (Exception e) {
			System.err.println("Initial Figure Construction Failed:");
			e.printStackTrace();
			return null;
		}
    	
    	// Construct the tool seperately (after figure construction is confirmed
		Constructor<?> constructors[] = toolClass.getConstructors();
		for (Constructor<?> constructor : constructors) {
			Class<?> parameters[] = constructor.getParameterTypes();
			if (parameters.length != 1) continue;
			try {
				return (Tool)constructor.newInstance(f);
			} catch (Exception ex) {continue;}
		}
		return null;
	}

	protected JToolBar getToolbar(String name, int priority) {
    	PriorityToolbar pToolbar = toolbars.get(name);
    	if (pToolbar == null) {
    		pToolbar = new PriorityToolbar(new JToolBar(), priority);
    		pToolbar.toolbar.setName(name);
    		toolbars.put(name, pToolbar);
    	} else if (pToolbar.priority < priority) {
    		pToolbar.priority = priority;
    	}
    	return pToolbar.toolbar;
    }
    
    protected JToggleButton getToggleButton(Class<? extends Figure> figure) {
    	JToggleButton button = buttons.get(figure);
    	if (button == null) {
    		button = new JToggleButton();
    		buttons.put(figure, button);
    	}
    	return button;
    }
    
    public List<JToolBar> getToolbarList() {
    	Collection<PriorityToolbar> vals = toolbars.values();
    	PriorityToolbar bars[] = new PriorityToolbar[vals.size()];
    	vals.toArray(bars);
    	Arrays.sort(bars, new Comparator<PriorityToolbar>() {
			@Override
			public int compare(PriorityToolbar o1, PriorityToolbar o2) {
				return o1.priority - o2.priority;
			}
    	});
    	ArrayList<JToolBar> list = new ArrayList<JToolBar>(bars.length);
    	for (PriorityToolbar bar : bars) {
    		list.add(bar.toolbar);
    	}
    	return list;
    }
    
    public void updateVisibleButtons(List<Class<? extends Figure>> figures) {
    	
    	// Remove visiblity on all buttons
    	for (JToggleButton button : buttons.values()) {
    		button.setVisible(false);
    	}
    	
    	// Remove visiblity on all toolbars
    	for (PriorityToolbar toolBar : toolbars.values()) {
    		toolBar.toolbar.setVisible(false);
    	}
    	
    	// Add visiblity to buttons and toolbars as specified
    	for (Class<? extends Figure> figure : figures) {
    		JToggleButton button = buttons.get(figure);
    		if (button != null) {
    			button.setVisible(true);
    			Container parent = button.getParent();
    			if (parent != null) parent.setVisible(true);
    		}
    	}
    	
    	// Make sure default toolbar is always visible
    	getToolbar("Figures", 0).setVisible(true);
    }
    
}
